package pro.cherish.smartfile.component.event;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import pro.cherish.smartfile.common.enums.biz.TaskStatusEnum;
import pro.cherish.smartfile.component.FileHelper;
import pro.cherish.smartfile.component.FileManager;
import pro.cherish.smartfile.component.RedisFileHelper;
import pro.cherish.smartfile.config.websocket.WebSocketSender;
import pro.cherish.smartfile.module.dto.TaskDto;
import pro.cherish.smartfile.service.AttachmentChunkTempService;
import pro.cherish.smartfile.service.AttachmentService;

import java.io.File;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lys
 */
@Component
@Slf4j
public class ChunkEventListener implements ApplicationListener<ChunkMergeEvent> {
    @Value("${smart.file.check.strict:true}")
    Boolean checkStrict;
    @Autowired
    private FileManager fileManager;
    @Autowired
    private AttachmentService attachmentService;
    @Autowired
    private AttachmentChunkTempService attachmentChunkTempService;
    @Autowired
    private ConcurrentHashMap<String, WebSocketSender> senderMap;

    @Override
    public void onApplicationEvent(ChunkMergeEvent event) {
        log.info("接受合并事件 ChunkEvent" + event.getTaskDto());
        boolean failTaskNeedPutRedisQueue = event.isFailTaskNeedPutRedisQueue();
        TaskDto taskDto = event.getTaskDto();
        String taskId = taskDto.getId();
        Boolean mergeSuccess;
        // 锁
        try {
            if (RedisFileHelper.getInstance().tryMergeLock(taskId) == 1L) {
                boolean dbOk = false;
                boolean localExist = false;
                boolean localDbEq = false;
                if (attachmentService.exist(taskId)) {
                    log.info("附件DB检验 ---> 已入库");
                    dbOk = true;
                    String archiveFile = fileManager.getArchiveFile(taskId);
                    if (StrUtil.isNotBlank(archiveFile)) {
                        log.info("本地归档校验  ---> 本地归档存在");
                        localExist = true;
                        if (fileManager.archiveMd5CheckPass(taskId, new File(archiveFile))) {
                            log.info("本地归档MD5校验  ---> 本地归档MD5正确");
                            localDbEq = true;
                        }
                    }
                }
                boolean skip;
                if (checkStrict) {
                    skip = dbOk && localExist && localDbEq;
                } else {
                    skip = dbOk;
                }
                if (skip) {
                    log.info("已存在文件[{}],不再合并", taskId);
                }
                // 先清除再合并
                FileHelper.getInstance().clearArchive(taskDto.getUploadTime(), taskDto.getId());
                File archiveFile = null;
                try {
                    archiveFile = FileHelper.getInstance().merge(taskDto);
                    mergeSuccess = true;
                } catch (Exception e) {
                    mergeSuccess = false;
                    log.error(e.toString());
                }
                // 2)文件MD5校验
                boolean lastResult = mergeSuccess && fileManager.archiveMd5CheckPass(taskId, archiveFile);
                String notifyMsg;
                if (lastResult) {
                    notifyMsg = StrUtil.format("文件[{}]合并成功了", taskDto.getFilename());
                    log.info("文件[{}]合并成功，开始清理临时信息和归档入库并且通知用户", taskId);
                    // 3-1)归档入库
                    attachmentService.saveAttachment(fileManager.buildAttachment(taskDto));
                    // 4)清理 chunk 本地文件存储
//                    FileHelper.getInstance().clearTemp(taskDto.getIdentify());
                    // 5)清理 chunk redis存储
                    RedisFileHelper.getInstance().removeAllChunk(taskDto.getId());
                    // 6)清理任务 redis存储
                    RedisFileHelper.getInstance().removeTask(taskId);
                    // 7)清理临时的DB
                    attachmentChunkTempService.removeAttachmentTemp(taskId);
                } else {
                    notifyMsg = "文件合并失败";
                    taskDto.setStatus(TaskStatusEnum.FILE_ARCHIVE_FAIL.getCode());
                    RedisFileHelper.getInstance().saveTaskOrUpd(taskDto);
                    if (failTaskNeedPutRedisQueue) {
                        // 放入失败队列，供后续定时消费
                        RedisFileHelper.getInstance().produceMergeFailTask(taskDto);
                    }
                }
                // 7)通知用户文件处理好了
                WebSocketSender sender = senderMap.get(taskDto.getUserId());
                if (sender != null) {
                    sender.sendData(notifyMsg);
                } else {
                    log.error("用户[{}]的websocket连接断开，不处理", taskDto.getUserId());
                }
            } else {
                log.info("文件[{}]merge未获取到锁，退出", taskId);
                return;
            }
        } finally {
            // 解锁
            RedisFileHelper.getInstance().releaseMergeLock(taskId);
        }
    }
}